<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- eventsandfilters.qdoc -->
  <title>The Event System | Qt Core 5.12.3</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.12</a></td><td ><a href="qtcore-index.html">Qt Core</a></td><td >The Event System</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtcore-index.html">Qt 5.12.3 参考指南</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">目录</a></h3>
<ul>
<li class="level1"><a href="#how-events-are-delivered">如何交付事件</a></li>
<li class="level1"><a href="#event-types">事件类型</a></li>
<li class="level1"><a href="#event-handlers">事件处理程序</a></li>
<li class="level1"><a href="#event-filters">事件过滤器</a></li>
<li class="level1"><a href="#sending-events">发送事件</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">事件系统</h1>
<span class="subtitle"></span>
<!-- $$$eventsandfilters.html-description -->
<div class="descr"> <a name="details"></a>
<p>在Qt中，事件是来自抽象的 <a href="qevent.html">QEvent</a> 
类的对象，它表示应用程序内部或外部活动导致的事件，应用程序需要了解这些事件。事件可以由 <a href="qobject.html">QObject</a> 
子类的任何实例接收和处理，但是它们与组件<span lang="zh-cn">（widget）</span>特别相关。本文档描述如何在典型应用程序中交付和处理事件。</p>
<a name="how-events-are-delivered"></a>
<h2 id="how-events-are-delivered">如何交付事件</h2>
<p>当一个事件发生时，Qt通过构造适当的 <a href="qevent.html">QEvent</a> 
子类的实例来创建一个事件对象来表示它，并通过调用它的 <a href="qobject.html#event">event()</a> 
函数将它传递给QObject的一个特定实例(或它的一个子类)。</p>
<p>此函数不处理事件本身;基于所交付的事件类型，它为特定类型的事件调用事件处理程序，并根据事件是否被接受或忽略发送响应。</p>
<p>一些事件，如 <a href="../qtgui/qmouseevent.html">QMouseEvent</a> <span lang="zh-cn">
和</span> <a href="../qtgui/qkeyevent.html">QKeyEvent</a>，来自窗口系统;有些，如 <a href="qtimerevent.html">QTimerEvent</a>，来自其他来源;有些来自应用程序本身。</p>
<a name="event-types"></a>
<h2 id="event-types">事件类型</h2>
<p>M大多数事件类型都有特殊的类，尤其是 <a href="../qtgui/qresizeevent.html">QResizeEvent</a><span lang="zh-cn">、</span> <a href="../qtgui/qpaintevent.html">QPaintEvent</a><span lang="zh-cn">、</span> <a href="../qtgui/qmouseevent.html">QMouseEvent</a><span lang="zh-cn">、</span> <a href="../qtgui/qkeyevent.html">QKeyEvent</a><span lang="zh-cn">以及</span> <a href="../qtgui/qcloseevent.html">QCloseEvent</a>。每个类都继承了 <a href="qevent.html">QEvent</a> 
并添加了特定于事件的函数。例如， <a href="../qtgui/qresizeevent.html">QResizeEvent</a> 添加 <a href="../qtgui/qresizeevent.html#size">size()</a> 
<span lang="zh-cn">和</span> <a href="../qtgui/qresizeevent.html#oldSize">oldSize()</a> 
以使<span lang="zh-cn">组件(widget)</span>能够发现它们的维度是如何更改的。</p>
<p>有些类支持多个实际事件类型。 <a href="../qtgui/qmouseevent.html">QMouseEvent</a> 
支持鼠标按键、双击、移动和其他相关操作。</p>
<p>每个事件都有一个关联的类型(在 <a href="qevent.html#Type-enum">QEvent::Type</a>中定义)，可以将其用作运行时类型信息的方便来源，以便快速确定给定事件对象是由哪个子类构造的。</p>
<p>由于程序需要以多种复杂的方式进行响应，Qt的事件交付机制是灵活的。 <a href="qcoreapplication.html#notify">QCoreApplication::notify</a>() 
的文档简明地讲述了整个<span lang="zh-cn">关于这方面的事情</span>;<i>Qt Quarterly<span lang="zh-cn">（Qt 
季刊）</span></i> <span lang="zh-cn">的一片文章</span> <span lang="zh-cn">《</span><a href="http://doc.qt.io/archives/qq/qq11-events.html"><span lang="zh-cn">再聊一下Qt事件</span></a><span lang="zh-cn">》</span>
<span lang="zh-cn">详细的讲了这方面内容</span>。<span lang="zh-cn">当然</span>这里我们<span lang="zh-cn">已为</span>95%的应用程序提供足够的解释。</p>
<a name="event-handlers"></a>
<h2 id="event-handlers">事件处理程序</h2>
<p>事件传递的通常方式是调用虚函数。例如， <a href="../qtgui/qpaintevent.html">QPaintEvent</a> 是通过调用 <a href="../qtwidgets/qwidget.html#paintEvent">QWidget::paintEvent</a>()来传递的。这个虚拟函数负责做出适当的反应，通常是通过重新绘制组件（widget）。如果在虚函数的实现中没有执行所有必要的工作，则可能需要调用基类的实现。</p>
<p>例如，下面的代码处理自定义复选框小部件上的鼠标左键单击，同时将所有其他按钮单击传递给基本的 <a href="../qtwidgets/qcheckbox.html">QCheckBox</a> 
类:</p>
<pre class="cpp">

  <span class="type">void</span> MyCheckBox<span class="operator">::</span>mousePressEvent(<span class="type"><a href="../qtgui/qmouseevent.html">QMouseEvent</a></span> <span class="operator">*</span>event)
  {
      <span class="keyword">if</span> (event<span class="operator">-</span><span class="operator">&gt;</span>button() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="qt.html">Qt</a></span><span class="operator">::</span>LeftButton) {
          <span class="comment">// <span lang="zh-cn">处理左侧鼠标</span></span>
      } <span class="keyword">else</span> {
          <span class="comment">// 将其他按钮传递给基类</span>
          <span class="type"><a href="../qtwidgets/qcheckbox.html">QCheckBox</a></span><span class="operator">::</span>mousePressEvent(event);
      }
  }

</pre>
<p>
如果您想替换基类的函数，必须自己实现所有内容。另一方面，如果您只想扩展基类的功能，那么不但可以扩展功能，还可以调用基类来获得您不想处理的任何情况下的默认行为。</p>
<p>
有时，没有这样一个特定于事件的函数，或者特定于事件的函数不够。最常见的例子是按Tab键。通常情况下，QWidget会拦截这些选项来移动键盘焦点，但是有一些组件（widget）本身需要Tab键。<span lang="zh-cn">（该段请参照原文）</span></p>
<p>这些对象可以重新实现通用事件处理程序 <a href="qobject.html#event">QObject::event</a>() 
，或者在通常的处理之前或之后执行它们的事件处理，或者可以完全替换函数<span lang="zh-cn">。</span> 
一个非常不寻常的组件，既解释制表符的同时又有一个特定于应用程序的自定义事件的组件，可能包含以下<a href="qobject.html#event">event()</a> 
函数:</p>
<pre class="cpp">

  bool MyWidget<span class="operator">::</span>event(<span class="type"><a href="qevent.html">QEvent</a></span> <span class="operator">*</span>event)
  {
      <span class="keyword">if</span> (event<span class="operator">-</span><span class="operator">&gt;</span>type() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress) {
          <span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span>ke <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span><span class="operator">&gt;</span>(event);
          <span class="keyword">if</span> (ke<span class="operator">-</span><span class="operator">&gt;</span>key() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="qt.html">Qt</a></span><span class="operator">::</span>Key_Tab) {
              <span class="comment">// 此处的特殊制表符处理</span>
              <span class="keyword">return</span> <span class="keyword">true</span>;
          }
      } <span class="keyword">else</span> <span class="keyword">if</span> (event<span class="operator">-</span><span class="operator">&gt;</span>type() <span class="operator">=</span><span class="operator">=</span> MyCustomEventType) {
          MyCustomEvent <span class="operator">*</span>myEvent <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span>MyCustomEvent <span class="operator">*</span><span class="operator">&gt;</span>(event);
          <span class="comment">// 这里的自定义事件处理</span>
          <span class="keyword">return</span> <span class="keyword">true</span>;
      }

      <span class="keyword">return</span> <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span><span class="operator">::</span>event(event);
  }

</pre>
<p>注意，对于所有未处理的情况， <a href="../qtwidgets/qwidget.html#event">QWidget::event</a>() 
仍然被调用，并且返回值指示是否处理了事件;true值阻止事件被发送到其他对象。</p>
<a name="event-filters"></a>
<h2 id="event-filters">事件过滤器</h2>
<p>有时，一个对象需要查看并可能拦截传递给另一个对象的事件。例如，对话框通常希望过滤某些组件的按键;例如，修改Return键处理。</p>
<p>The <a href="qobject.html#installEventFilter">QObject::installEventFilter</a>() 
函数通过设置<i>事件过滤器</i>来实现这一点，从而使指定的过滤器对象在其 <a href="qobject.html#eventFilter">QObject::eventFilter</a>() 
函数中接收目标对象的事件。事件过滤器在目标对象处理事件之前处理事件，允许它根据需要检查和丢弃事件。可以使用<a href="qobject.html#removeEventFilter">QObject::removeEventFilter</a>() 
函数删除现有的事件过滤器。</p>
<p>当调用筛选器对象的 <a href="qobject.html#eventFilter">eventFilter()</a> 
实现时，它可以接受或拒绝事件，并允许或拒绝事件的进一步处理。如果所有事件过滤器都允许对事件进行进一步处理(通过每次返回 <code>false<span lang="zh-cn">）。</span></code> 
，则将事件发送到目标对象本身。如果其中之一停止处理(通过返回 <code>true</code>))，则目标和任何后续事件筛选器将根本看不到事件。</p>
<pre class="cpp">

  bool FilterObject<span class="operator">::</span>eventFilter(<span class="type"><a href="qobject.html">QObject</a></span> <span class="operator">*</span>object<span class="operator">,</span> <span class="type"><a href="qevent.html">QEvent</a></span> <span class="operator">*</span>event)
  {
      <span class="keyword">if</span> (object <span class="operator">=</span><span class="operator">=</span> target <span class="operator">&amp;</span><span class="operator">&amp;</span> event<span class="operator">-</span><span class="operator">&gt;</span>type() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress) {
          <span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span>keyEvent <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span><span class="operator">&gt;</span>(event);
          <span class="keyword">if</span> (keyEvent<span class="operator">-</span><span class="operator">&gt;</span>key() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="qt.html">Qt</a></span><span class="operator">::</span>Key_Tab) {
              <span class="comment">// 特殊标签处理</span>
              <span class="keyword">return</span> <span class="keyword">true</span>;
          } <span class="keyword">else</span>
              <span class="keyword">return</span> <span class="keyword">false</span>;
      }
      <span class="keyword">return</span> <span class="keyword">false</span>;
  }

</pre>
<p><code>上面的代码显示了截获发送到特定目标组件的Tab键按下事件的另一种方法。在这种情况下，过滤器处理相关事件并返回true</code> <code>
，以阻止它们进一步被处理。所有其他事件都被忽略，过滤器返回</code> <code>false</code> <code>
，允许通过安装在其上的任何其他事件过滤器将它们发送到目标小部件。</code></p>
<p>还可以通过在<a href="../qtwidgets/qapplication.html">QApplication</a> 
<span lang="zh-cn">或</span> <a href="qcoreapplication.html">QCoreApplication</a>对象上安装事件过滤器来过滤整个应用程序的<i>all</i> 
事件。这样的全局事件过滤器在对象特定的过滤器之前调用。这是非常强大的，但它也减慢了整个应用程序中每个事件的事件交付;通常应该使用讨论的其他技术。 </p>
<a name="sending-events"></a>
<h2 id="sending-events">Sending Events</h2>
<p>许多应用程序都希望创建和发送自己的事件。通过构造合适的事件对象，并使用<a href="qcoreapplication.html#sendEvent">QCoreApplication::sendEvent</a>()
<span lang="zh-cn">和</span> <a href="qcoreapplication.html#postEvent">QCoreApplication::postEvent</a>()发送它们，您可以以与Qt自己的事件循环完全相同的方式发送事件。 </p>
<p>&nbsp;<a href="qcoreapplication.html#sendEvent">sendEvent()</a>立即处理事件。当它返回时，事件过滤器和/或对象本身已经处理了事件。对于许多事件类，有一个名为<a href="qevent.html#accepted-prop">isAccepted()</a>的函数，它告诉您最后一个调用的处理程序是否接受或拒绝了事件。</p>
<p><a href="qcoreapplication.html#postEvent">postEvent()</a>将事件发布到队列中，以供以后调度。下一次Qt的主事件循环运行时，它将分发所有已发布的事件，并进行一些优化。例如，如果有多个调整大小事件，则将它们压缩为一个。这同样适用于绘制事件:<a href="../qtwidgets/qwidget.html#update">QWidget::update</a>()调用<a href="qcoreapplication.html#postEvent">postEvent()</a>，它消除了闪烁并通过避免多次重绘来提高速度。</p>
<p><a href="qcoreapplication.html#postEvent">postEvent()</a>也用于对象初始化期间，因为提交的事件通常在对象初始化完成后很快被分派。在实现小部件时，重要的是要认识到事件可以在其生命周期中很早就交付，因此在其构造函数中，一定要在有可能接收到事件之前尽早初始化成员变量。</p>
<p>&nbsp;<a href="qevent.html">QEvent</a> 要创建自定义类型的事件，您需要定义一个事件编号，该编号必须大于<a href="qevent.html#Type-enum">QEvent::User</a>，并且您可能需要继承<a href="qevent.html">QEvent</a>的子类，以便传递关于您的自定义事件的特定信息。有关更多细节，请参见<a href="qevent.html">QEvent</a>文档。</p>
</div>
<!-- @@@eventsandfilters.html -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>
